home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  48.4 KB  |  2,089 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * mem.c:: routines for managing memory regions
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "fasttext.h" /* for line A stuff */
  13.  
  14. #ifndef VgetSize
  15. #if defined(__GNUC__) && defined(trap_14_ww)
  16. #define    VgetSize(mode) (long)trap_14_ww((short)91,(short)(mode))
  17. #define Vsetmode(mode) (short)trap_14_ww((short)88,(short)(mode))
  18. #else
  19. extern long xbios();
  20. #define VgetSize(mode) xbios(91, (short)(mode))
  21. #define Vsetmode(mode) xbios(88, (short)(mode))
  22. #endif
  23. #endif
  24.  
  25. static long core_malloc P_((long, int));
  26. static void core_free P_((long));
  27. static void terminateme P_((int code));
  28.  
  29. /* macro for testing whether a memory region is free */
  30. #define ISFREE(m) ((m)->links == 0)
  31.  
  32. /*
  33.  * list of shared text regions currently being executed
  34.  */
  35. SHTEXT *text_reg = 0;
  36.  
  37. /*
  38.  * initialize memory routines
  39.  */
  40.  
  41. /* initial number of memory regions */
  42. #define NREGIONS ((8*1024)/sizeof(MEMREGION))
  43.  
  44. /* number of new regions to allocate when the initial ones are used up */
  45. #define NEWREGIONS ((8*1024)/sizeof(MEMREGION))
  46.  
  47. static MEMREGION use_regions[NREGIONS+1];
  48. MEMREGION *rfreelist;
  49.  
  50. /* variable for debugging purposes; number of times we've needed
  51.  * to get new regions
  52.  */
  53. int num_reg_requests = 0;
  54.  
  55. /* these variables are set in init_core(), and used in
  56.  * init_mem()
  57.  */
  58. static ulong scrnsize, scrnplace;
  59. static SCREEN *vscreen;
  60.  
  61. void
  62. init_mem()
  63. {
  64.     int i;
  65.     MEMREGION *r;
  66.     long newbase;
  67.  
  68.     use_regions[NREGIONS].next = 0;
  69.     for (i = 0; i < NREGIONS; i++) {
  70.         use_regions[i].next = &use_regions[i+1];
  71.     }
  72.     rfreelist = use_regions;
  73.  
  74.     init_core();
  75.     init_swap();
  76.  
  77.     init_tables();            /* initialize MMU constants */
  78.  
  79.     /* mark all the regions in the core & alt lists as "invalid" */
  80.     for (r = *core; r; r = r->next) {
  81.         mark_region(r,PROT_I);
  82.     }
  83.     for (r = *alt; r; r = r->next) {
  84.         mark_region(r,PROT_I);
  85.     }
  86.  
  87.     /* make sure the screen is set up properly */
  88.     newbase = s_realloc(scrnsize);
  89.  
  90.     /* if we did get a new screen, point the new screen
  91.      * at the right place after copying the data
  92.      * if possible, save the screen to another buffer,
  93.      * since if the new screen and old screen overlap
  94.      * the blit will look very ugly.
  95.      * Note that if the screen isn't moveable, then we set
  96.      * scrnsize to a ridiculously large value, and so the
  97.      * s_realloc above failed.
  98.      */
  99.     if (newbase) {
  100.     /* find a free region for temp storage */
  101.         for (r = *core; r; r = r->next) {
  102.             if (ISFREE(r) && r->len >= scrnsize)
  103.                 break;
  104.         }
  105.  
  106.         if (r) {
  107.             quickmove((char *)r->loc, (char *)scrnplace, scrnsize);
  108.             Setscreen((void *)r->loc, (void *)r->loc, -1);
  109.             Vsync();
  110.             quickmove((char *)newbase, (char *)r->loc, scrnsize);
  111.         } else {
  112.             quickmove((char *)newbase, (char *)scrnplace, scrnsize);
  113.         }
  114.         Setscreen((void *)newbase, (void *)newbase, -1);
  115.     /* fix the cursor */
  116.         Cconws("\r\n"); 
  117.     }
  118. }
  119.  
  120. void
  121. restr_screen()
  122. {
  123.   long base = (long) Physbase ();
  124.   MEMREGION *r;
  125.  
  126.   if (base != scrnplace)
  127.     {
  128.       for (r = *core; r; r = r->next)
  129.     {
  130.       if (ISFREE (r) && r->len >= scrnsize)
  131.         break;
  132.     }
  133.       if (r)
  134.     {
  135.       quickmove ((char *) r->loc, (char *) base, scrnsize);
  136.       Setscreen ((void *) r->loc, (void *) r->loc, -1);
  137.       Vsync ();
  138.       quickmove ((char *) scrnplace, (char *) r->loc, scrnsize);
  139.     }
  140.       else
  141.     quickmove ((char *) scrnplace, (char *) base, scrnsize);
  142.       Setscreen ((void *) scrnplace, (void *) scrnplace, -1);
  143.       Cconws ("\r\n"); 
  144.     }
  145. }
  146.  
  147. /*
  148.  * init_core(): initialize the core memory map (normal ST ram) and also
  149.  * the alternate memory map (fast ram on the TT)
  150.  */
  151.  
  152. static MEMREGION *_core_regions = 0, *_alt_regions = 0,
  153.     *_ker_regions = 0;
  154.  
  155. MMAP core = &_core_regions;
  156. MMAP alt = &_alt_regions;
  157. MMAP ker = &_ker_regions;
  158.  
  159. /* note: add_region must adjust both the size and starting
  160.  * address of the region being added so that memory is
  161.  * always properly aligned
  162.  */
  163.  
  164. int
  165. add_region(map, place, size, mflags)
  166.     MMAP map;
  167.     ulong place, size;
  168.     unsigned mflags;    /* initial flags for region */
  169. {
  170.       MEMREGION *m;
  171.     ulong trimsize;
  172.  
  173.     TRACELOW(("add_region(map=%lx,place=%lx,size=%lx,flags=%x)",
  174.         map,place,size,mflags));
  175.  
  176.     m = new_region();
  177.     if (m == 0)
  178.         return 0;    /* failure */
  179.     m->links = 0;
  180.  
  181.     if (place & MASKBITS) {
  182.         /* increase place & shorten size by the amount we're trimming */
  183.         trimsize = (MASKBITS+1) - (place & MASKBITS);
  184.         if (size <= trimsize) goto lose;
  185.         size -= trimsize;
  186.         place += trimsize;
  187.     }
  188.  
  189.     /* now trim size DOWN to a multiple of pages */
  190.     if (size & MASKBITS) size &= ~MASKBITS;
  191.  
  192.     /* only add if there's anything left */
  193.     if (size) {
  194.         m->len = size;
  195.         m->loc = place;
  196.         m->next = *map;
  197.         m->mflags = mflags;
  198.         *map = m;
  199.     }
  200.     else {
  201.         /* succeed but don't do anything; dispose of region */
  202. lose:        dispose_region(m);
  203.     }
  204.     return 1;    /* success */
  205. }
  206.  
  207. static long
  208. core_malloc(amt, mode)
  209.     long amt;
  210.     int mode;
  211. {
  212.     static int mxalloc = -1;    /* does GEMDOS know about Mxalloc? */
  213.     long ret;
  214.  
  215.     if (mxalloc < 0) {
  216.         ret = (long)Mxalloc(-1L, 0);
  217.         if (ret == -32) mxalloc = 0;    /* unknown function */
  218.         else if (ret >= 0) mxalloc = 1;
  219.         else {
  220.             ALERT("GEMDOS returned %ld from Mxalloc", ret);
  221.             mxalloc = 0;
  222.         }
  223.     }
  224.     if (mxalloc)
  225.         return (long) Mxalloc(amt, mode);
  226.     else if (mode == 1)
  227.         return 0L;
  228.     else
  229.         return (long) Malloc(amt);
  230. }
  231.  
  232. static void
  233. core_free(where)
  234.     long where;
  235. {
  236.     Mfree((void *)where);
  237. }
  238.  
  239. void
  240. init_core()
  241. {
  242.     extern int FalconVideo;    /* set in main.c */
  243.     int scrndone = 0;
  244.     ulong size;
  245.     ulong place;
  246.     ulong temp;
  247.     void *tossave;
  248.  
  249.     tossave = (void *)core_malloc((long)TOS_MEM, 0);
  250.     if (!tossave) {
  251.         FATAL("Not enough memory to run MiNT");
  252.     }
  253.  
  254. /* initialize kernel memory */
  255.     place = (ulong)core_malloc(KERNEL_MEM, 3);
  256.     if (place != 0) {
  257.         nalloc_arena_add((void *)place,KERNEL_MEM);
  258.     }
  259.  
  260. /*
  261.  * find out where the screen is. We want to manage the screen
  262.  * memory along with all the other memory, so that Srealloc()
  263.  * can be used by the XBIOS to allocate screens from the
  264.  * end of memory -- this avoids fragmentation problems when
  265.  * changing resolutions.
  266.  */
  267. /* Note, however, that some graphics boards (e.g. Matrix)
  268.  * are unable to change the screen address. We fake out the
  269.  * rest of our code by pretending to have a really huge
  270.  * screen that can't be changed.
  271.  */
  272.     scrnplace = (long)Physbase();
  273.  
  274.     vscreen = (SCREEN *)((char *)lineA0() - 346);
  275.     if (FalconVideo) {
  276.     /* the Falcon can tell us the screen size */
  277.         scrnsize = VgetSize(Vsetmode(-1));
  278.     } else {
  279.     /* otherwise, use the line A variables */
  280.         scrnsize = (vscreen->maxy+1)*(long)vscreen->linelen;
  281.     }
  282.  
  283. /* check for a graphics card with fixed screen location */
  284. #define phys_top_st (*(ulong *)0x42eL)
  285.  
  286.     if (scrnplace >= phys_top_st) {
  287. /* screen isn't in ST RAM */
  288.         scrnsize = 0x7fffffffUL;
  289.         scrndone = 1;
  290.     } else {
  291.         temp = (ulong)core_malloc(scrnsize+256L, 0);
  292.         if (temp) {
  293.             (void)Setscreen((void *)-1L,
  294.                     (void *)((temp+511)&(0xffffff00L)), -1);
  295.             if ((long)Physbase() != ((temp+511)&(0xffffff00L))) {
  296.                 scrnsize = 0x7fffffffUL;
  297.                 scrndone = 1;
  298.             }
  299.             (void)Setscreen((void *)-1L, (void *)scrnplace, -1);
  300.             core_free(temp);
  301.         }
  302.     }
  303.  
  304. /* initialize ST RAM */
  305.     size = (ulong)core_malloc(-1L, 0);
  306.     while (size > 0) {
  307.         place = (ulong)core_malloc(size, 0);
  308.         if (!scrndone && (place + size == scrnplace)) {
  309.             size += scrnsize;
  310.             scrndone = 1;
  311.         }
  312.         if (!add_region(core, place, size, M_CORE))
  313.             FATAL("init_mem: unable to add a region");
  314.         size = (ulong)core_malloc(-1L, 0);
  315.     }
  316.  
  317.     if (!scrndone) {
  318.         (void)add_region(core, scrnplace, scrnsize, M_CORE);
  319.     }
  320.  
  321. /* initialize alternate RAM */
  322.     size = (ulong)core_malloc(-1L, 1);
  323.     while (size > 0) {
  324.         place = (ulong)core_malloc(size, 1);
  325.         if (!add_region(alt, place, size, M_ALT))
  326.             FATAL("init_mem: unable to add a region");
  327.         size = (ulong)core_malloc(-1L, 1);
  328.     }
  329.  
  330.     (void)Mfree(tossave);        /* leave some memory for TOS to use */
  331. }
  332.  
  333. /*
  334.  * init_swap(): initialize the swap area; for now, this does nothing
  335.  */
  336.  
  337. MEMREGION *_swap_regions = 0;
  338. MMAP swap = &_swap_regions;
  339.  
  340. void
  341. init_swap()
  342. {
  343. }
  344.  
  345. /*
  346.  * routines for allocating/deallocating memory regions
  347.  */
  348.  
  349. /*
  350.  * new_region returns a new memory region descriptor, or NULL
  351.  */
  352.  
  353. MEMREGION *
  354. new_region()
  355. {
  356.     MEMREGION *m, *newfrees;
  357.     int i;
  358.  
  359.     m = rfreelist;
  360.     if (!m) {
  361.         ALERT("new_region: ran out of free regions");
  362.         return 0;
  363.     }
  364.     assert(ISFREE(m));
  365.     rfreelist = m->next;
  366.     m->next = 0;
  367.  
  368. /* if we're running low on free regions, allocate some more
  369.  * we have to do this with at least 1 free region left so that get_region
  370.  * has a chance of working
  371.  */
  372.     if (rfreelist && !rfreelist->next) {
  373.         MEMREGION *newstuff;
  374.  
  375.         TRACELOW(("get_region: getting new region descriptors"));
  376.         newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  377.         if (!newstuff)
  378.             newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  379.         if (!newstuff)
  380.             newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION), PROT_S);
  381.         newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
  382.         if (newfrees) {
  383.             num_reg_requests++;
  384.             newfrees[NEWREGIONS-1].next = 0;
  385.             newfrees[NEWREGIONS-1].links = 0;
  386.             for (i = 0; i < NEWREGIONS-1; i++) {
  387.                 newfrees[i].next = &newfrees[i+1];
  388.                 newfrees[i].links = 0;
  389.             }
  390.             rfreelist = newfrees;
  391.         } else {
  392.             DEBUG(("couldn't get new region descriptors!"));
  393.         }
  394.     }
  395.  
  396.     return m;
  397. }
  398.  
  399. /*
  400.  * dispose_region destroys a memory region descriptor
  401.  */
  402.  
  403. void
  404. dispose_region(m)
  405.     MEMREGION *m;
  406. {
  407.     m->next = rfreelist;
  408.     rfreelist = m;
  409. }
  410.  
  411. #if 0
  412. /* notused: see dosmem.c */
  413. /*
  414.  * change_prot_status: change the status of a region to 'newmode'.  We're
  415.  * given its starting address, not its region structure pointer, so we have
  416.  * to find the region pointer; since this is illegal if proc doesn't own
  417.  * the region, we know we'll find the region struct pointer in proc->mem.
  418.  *
  419.  * If the proc doesn't own it, you get EACCDN.  There are no other errors.
  420.  * God help you if newmode isn't legal!
  421.  */
  422.  
  423. long
  424. change_prot_status(proc,start,newmode)
  425. PROC *proc;
  426. long start;
  427. int newmode;
  428. {
  429.     MEMREGION **mr;
  430.     int i;
  431.  
  432.     /* return EACCDN if you don't own the region in question */
  433.     if (!proc->mem) return EACCDN;
  434.  
  435.     for (mr = proc->mem, i = 0; i < proc->num_reg; i++, mr++) {
  436.     if ((*mr)->loc == start) goto found;
  437.     }
  438.     return EACCDN;
  439.  
  440. found:
  441.     mark_region(*mr,newmode);
  442.     return E_OK;
  443. }
  444. #endif
  445.  
  446. /*
  447.  * virtaddr
  448.  * attach_region(proc, reg): attach the region to the given process:
  449.  * returns the address at which it was attached, or NULL if the process
  450.  * cannot attach more regions. The region link count is incremented if
  451.  * the attachment is successful.
  452.  */
  453.  
  454. virtaddr
  455. attach_region(proc, reg)
  456.     PROC *proc;
  457.     MEMREGION *reg;
  458. {
  459.     int i;
  460.     MEMREGION **newmem;
  461.     virtaddr *newaddr;
  462.  
  463.     TRACELOW(("attach_region %lx len %lx to pid %d",
  464.         reg->loc, reg->len, proc->pid));
  465.  
  466.     if (!reg || !reg->loc) {
  467.         ALERT("attach_region: attaching a null region??");
  468.         return 0;
  469.     }
  470.  
  471. again:
  472.     for (i = 0; i < proc->num_reg; i++) {
  473.         if (!proc->mem[i]) {
  474.             assert(proc->addr[i] == 0);
  475.             reg->links++;
  476.             proc->mem[i] = reg;
  477.             proc->addr[i] = (virtaddr) reg->loc;
  478.             mark_proc_region(proc,reg,PROT_P);
  479.             return proc->addr[i];
  480.         }
  481.     }
  482.  
  483. /* Hmmm, OK, we have to expand the process' memory table */
  484.     TRACELOW(("Expanding process memory table"));
  485.     i = proc->num_reg + NUM_REGIONS;
  486.  
  487.     newmem = kmalloc(i * SIZEOF(MEMREGION *));
  488.     newaddr = kmalloc(i * SIZEOF(virtaddr));
  489.  
  490.     if (newmem && newaddr) {
  491.     /*
  492.      * We have to use temps while allocating and freeing mem
  493.      * and addr so the memory protection code won't walk this
  494.      * process' memory list in the middle.
  495.      */
  496.         void *pmem, *paddr;
  497.  
  498.     /* copy over the old address mapping */
  499.         for (i = 0; i < proc->num_reg; i++) {
  500.             newmem[i] = proc->mem[i];
  501.             newaddr[i] = proc->addr[i];
  502.             if (newmem[i] == 0)
  503.                 assert(newaddr[i] == 0);
  504.         }
  505.     /* initialize the rest of the tables */
  506.         for(; i < proc->num_reg + NUM_REGIONS; i++) {
  507.             newmem[i] = 0;
  508.             newaddr[i] = 0;
  509.         }
  510.     /* free the old tables (carefully! for memory protection) */
  511.         pmem = proc->mem;
  512.         paddr = proc->addr;
  513.         proc->mem = NULL;
  514.         proc->addr = NULL;
  515.         kfree(pmem); kfree(paddr);
  516.         proc->mem = newmem;
  517.         proc->addr = newaddr;
  518.         proc->num_reg += NUM_REGIONS;
  519.     /* this time we will succeed */
  520.         goto again;
  521.     } else {
  522.         if (newmem) kfree(newmem);
  523.         if (newaddr) kfree(newaddr);
  524.         DEBUG(("attach_region: failed"));
  525.         return 0;
  526.     }
  527. }
  528.  
  529. /*
  530.  * detach_region(proc, reg): remove region from the procedure's address
  531.  * space. If no more processes reference the region, return it to the
  532.  * system. Note that we search backwards, so that the most recent
  533.  * attachment of memory gets detached!
  534.  */
  535.  
  536. void
  537. detach_region(proc, reg)
  538.     PROC *proc;
  539.     MEMREGION *reg;
  540. {
  541.     int i;
  542.  
  543.     if (!reg) return;
  544.  
  545.     TRACELOW(("detach_region %lx len %lx from pid %d",
  546.         reg->loc, reg->len, proc->pid));
  547.  
  548.     for (i = proc->num_reg - 1; i >= 0; i--) {
  549.         if (proc->mem[i] == reg) {
  550.             reg->links--;
  551.             proc->mem[i] = 0; proc->addr[i] = 0;
  552.             if (reg->links == 0) {
  553.                 free_region(reg);
  554.             }
  555.             else {
  556.                 /* cause curproc's table to be updated */
  557.                 mark_proc_region(proc,reg,PROT_I);
  558.             }
  559.             return;
  560.         }
  561.     }
  562.     DEBUG(("detach_region: region not attached"));
  563. }
  564.  
  565. /*
  566.  * get_region(MMAP map, ulong size, int mode) -- allocate a new region of the
  567.  * given size in the given memory map. if no region big enough is available,
  568.  * return NULL, otherwise return a pointer to the region.
  569.  * "mode" tells us about memory protection modes
  570.  *
  571.  * the "links" field in the region is set to 1
  572.  *
  573.  * BEWARE: new_region may call get_region (indirectly), so we have to be
  574.  * _very_ careful with re-entrancy in this function
  575.  */
  576.  
  577. MEMREGION *
  578. get_region(map, size, mode)
  579.     MMAP map;
  580.     ulong size;
  581.     int mode;
  582. {
  583.     MEMREGION *m, *n, *nlast, *nfirstp, *s;
  584.  
  585.     TRACELOW(("get_region(%s,%lx,%x)",
  586.         (map == ker ? "ker" : (map == core ? "core" : "alt")),
  587.         size, mode));
  588.  
  589. /* precautionary measures */
  590.     if (size == 0) {
  591.         DEBUG(("request for 0 bytes??"));
  592.         size = 1;
  593.     }
  594.  
  595.     size = ROUND(size);
  596.  
  597.     sanity_check(map);
  598. /* exact matches are likely to be rare, so we pre-allocate a new
  599.  * region here; this helps us to avoid re-entrancy problems
  600.  * when new_region calls get_region
  601.  */
  602.     m = new_region();
  603.  
  604. /* We come back and try again if we found and freed any unattached shared
  605.  * text regions.
  606.  */
  607.     nfirstp = NULL;
  608. #if 0
  609. retry:
  610. #endif
  611.     n = *map;
  612. retry2:
  613.     s = nlast = NULL;
  614.  
  615.     while (n) {
  616.         if (ISFREE(n)) {
  617.             if (n->len == size) {
  618.                 if (m) dispose_region(m);
  619.                 n->links++;
  620.                 goto win;
  621.             }
  622.             else if (n->len > size) {
  623. /* split a new region, 'm', which will contain the free bytes after n */
  624.                 if (m) {
  625.                     m->next = n->next;
  626.                     n->next = m;
  627.                     m->mflags = n->mflags & M_MAP;
  628.                     m->loc = n->loc + size;
  629.                     m->len = n->len - size;
  630.                     n->len = size;
  631.                     n->links++;
  632.                     goto win;
  633.                 } else {
  634.                     DEBUG(("get_region: no regions left"));
  635.                     return 0;
  636.                 }
  637.             }
  638.             nlast = n;
  639. /* If this is an unattached shared text region, leave it as a last resort */
  640.         } else if (n->links == 0xffff && (n->mflags & M_SHTEXT)) {
  641.             if (!s) {
  642.                 s = n;
  643.                 nfirstp = nlast;
  644.             }
  645.         }
  646.         n = n->next;
  647.     }
  648.  
  649. /* Looks like we're out of free memory. Try freeing an unattached shared text
  650.  * region, and then try again to fill this request.
  651.  */
  652. #if 1
  653.     if (s && s->len < size) {
  654.         long lastsize = 0, end = 0;
  655.  
  656.         n = nlast = nfirstp;
  657.         if (!n || n->next != s)
  658.             n = s;
  659.         for (; n; n = n->next) {
  660.             if (ISFREE(n)) {
  661.                 if (end == n->loc) {
  662.                     lastsize += n->len;
  663.                 } else {
  664.                     s = NULL;
  665.                     nfirstp = nlast;
  666.                     lastsize = n->len;
  667.                 }
  668.                 nlast = n;
  669.                 end = n->loc + n->len;
  670.                 if (lastsize >= size) {
  671.                     break;
  672.                 }
  673.             } else if (n->links == 0xffff && (n->mflags & M_SHTEXT)) {
  674.                 if (end == n->loc) {
  675.                     if (!s)
  676.                         s = n;
  677.                     lastsize += n->len;
  678.                 } else {
  679.                     s = n;
  680.                     nfirstp = nlast;
  681.                     lastsize = n->len;
  682.                 }
  683.                 end = n->loc + n->len;
  684.                 if (lastsize >= size) {
  685.                     break;
  686.                 }
  687.             }
  688.         }
  689.         if (!n)
  690.             s = NULL;
  691.     }
  692.     if (s) {
  693.         s->links = 0;
  694.         free_region(s);
  695.         if (NULL == (n = nfirstp))
  696.             n = *map;
  697.         goto retry2;
  698.     }
  699. #else
  700.     if (s) {
  701.         s->links = 0;
  702.         free_region(s);
  703.         goto retry;
  704.     }
  705. #endif
  706.         
  707.     if (m)
  708.         dispose_region(m);
  709.  
  710.     TRACELOW(("get_region: no memory left in this map"));
  711.     return NULL;
  712.  
  713. win:
  714.     mark_region(n, mode & PROT_PROTMODE);
  715.     if (mode & M_KEEP) n->mflags |= M_KEEP;
  716.  
  717.     return n;
  718. }
  719.  
  720. /*
  721.  * free_region(MEMREGION *reg): free the indicated region. The map
  722.  * in which the region is contained is given by reg->mflags.
  723.  * the caller is responsible for making sure that the region
  724.  * really should be freed, i.e. that reg->links == 0.
  725.  *
  726.  * special things to do:
  727.  * if the region is a shared text region, we must close the
  728.  * associated file descriptor
  729.  */
  730.  
  731. void
  732. free_region(reg)
  733.     MEMREGION *reg;
  734. {
  735.     MMAP map;
  736.     MEMREGION *m;
  737.     SHTEXT *s, **old;
  738.  
  739.     if (!reg) return;
  740.  
  741.     assert(ISFREE(reg));
  742.  
  743.     if (reg->mflags & M_SHTEXT) {
  744.         TRACE(("freeing shared text region"));
  745.         old = &text_reg;
  746.         for(;;) {
  747.             s = *old;
  748.             if (!s) break;
  749.             if (s->text == reg) {
  750.                 if (s->f)
  751.                     do_close(s->f);
  752.                 *old = s->next;
  753.                 kfree(s);
  754.                 break;
  755.             }
  756.             old = &s->next;
  757.         }
  758.         if (!s) {
  759.             DEBUG(("No shared text entry for M_SHTEXT region??"));
  760.         }
  761.     }
  762.  
  763.     if (reg->mflags & M_CORE)
  764.         map = core;
  765.     else if (reg->mflags & M_ALT)
  766.         map = alt;
  767.     else if (reg->mflags & M_KER)
  768.         map = ker;
  769.     else {
  770.         FATAL("free_region: region flags not valid (%x)", reg->mflags);
  771.     }
  772.     reg->mflags &= M_MAP;
  773.  
  774. /* unhook any vectors pointing into this region */
  775.     unlink_vectors(reg->loc, reg->loc + reg->len);
  776.  
  777. /* BUG(?): should invalidate caches entries - a copyback cache could stuff
  778.  * things into freed memory.
  779.  *    cinv(reg->loc, reg->len);
  780.  */
  781.     m = *map;
  782.     assert(m);
  783.  
  784.     /* MEMPROT: invalidate */
  785.     if (map == core || map == alt)
  786.         mark_region(reg,PROT_I);
  787.  
  788.     if (m == reg) goto merge_after;
  789.  
  790. /* merge previous region if it's free and contiguous with 'reg' */
  791.  
  792. /* first, we find the region */
  793.     while (m && m->next != reg)
  794.         m = m->next;
  795.  
  796.     if (m == NULL) {
  797.         FATAL("couldn't find region %lx: loc: %lx len: %ld",
  798.             reg, reg->loc, reg->len);
  799.     }
  800.  
  801.     if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
  802.         m->len += reg->len;
  803.         assert(m->next == reg);
  804.         m->next = reg->next;
  805.         reg->next = 0;
  806.         dispose_region(reg);
  807.         reg = m;
  808.     }
  809.  
  810. /* merge next region if it's free and contiguous with 'reg' */
  811. merge_after:
  812.     m = reg->next;
  813.     if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
  814.         reg->len += m->len;
  815.         reg->next = m->next;
  816.         m->next = 0;
  817.         dispose_region(m);
  818.     }
  819.  
  820.     sanity_check(map);
  821. }
  822.  
  823. /*
  824.  * shrink_region(MEMREGION *reg, ulong newsize):
  825.  *   shrink region 'reg', so that it is now 'newsize' bytes long.
  826.  *   if 'newsize' is bigger than the region's current size, return EGSBF;
  827.  *   otherwise return 0.
  828.  */
  829.  
  830. long
  831. shrink_region(reg, newsize)
  832.     MEMREGION *reg;
  833.     ulong newsize;
  834. {
  835.     MEMREGION *n;
  836.     ulong diff;
  837.  
  838.  
  839.     newsize = ROUND(newsize);
  840.  
  841.     assert(reg->links > 0);
  842.  
  843.     if (!(reg->mflags & (M_CORE | M_ALT | M_KER))) {
  844.         FATAL("shrink_region: bad region flags (%x)", reg->mflags);
  845.     }
  846.  
  847. /* shrinking to 0 is the same as freeing */
  848.     if (newsize == 0) {
  849.         detach_region(curproc, reg);
  850.         return 0;
  851.     }
  852.  
  853. /* if new size is the same as old size, don't do anything */
  854.     if (newsize == reg->len) {
  855.         return 0;    /* nothing to do */
  856.     }
  857.  
  858.     if (newsize > reg->len) {
  859.         DEBUG(("shrink_region: request to make region bigger"));
  860.         return EGSBF;    /* growth failure */
  861.     }
  862.  
  863. /* OK, we're going to free (reg->len - newsize) bytes at the end of
  864.    this block. If the block after us is already free, simply add the
  865.    space to that block.
  866.  */
  867.     n = reg->next;
  868.     diff = reg->len - newsize;
  869.  
  870.     if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
  871.         reg->len = newsize;
  872.         n->loc -= diff;
  873.         n->len += diff;
  874.         /* MEMPROT: invalidate the second half */
  875.         /* (part of it is already invalid; that's OK) */
  876.         mark_region(n,PROT_I);
  877.  
  878.         return 0;
  879.     }
  880.     else {
  881.         n = new_region();
  882.         if (!n) {
  883.             DEBUG(("shrink_region: new_region failed"));
  884.             return EINTRN;
  885.         }
  886.         reg->len = newsize;
  887.         n->loc = reg->loc + newsize;
  888.         n->len = diff;
  889.         n->mflags = reg->mflags & M_MAP;
  890.         n->next = reg->next;
  891.         reg->next = n;
  892.         /* MEMPROT: invalidate the new, free region */
  893.         mark_region(n,PROT_I);
  894.     }
  895.     return 0;
  896. }
  897.  
  898. /*
  899.  * max_rsize(map, deeded): return the length of the biggest free region
  900.  * in the given memory map, or 0 if no regions remain.
  901.  * needed is minimun amount needed, if != 0 try to keep unattached
  902.  * shared text regions, else count them all as free.
  903.  */
  904.  
  905. long
  906. max_rsize(map, needed)
  907.     MMAP map;
  908.     long needed;
  909. {
  910.     MEMREGION *m;
  911.     long size = 0, lastsize = 0, end = 0;
  912.  
  913.     if (needed) {
  914.         for (m = *map; m; m = m->next) {
  915.             if (ISFREE(m) ||
  916.                 (m->links == 0xfffe && !(m->mflags & M_SHTEXT))) {
  917.                 if (end == m->loc) {
  918.                     lastsize += m->len;
  919.                 } else {
  920.                     lastsize = m->len;
  921.                 }
  922.                 end = m->loc + m->len;
  923.                 if (lastsize > size) {
  924.                     size = lastsize;
  925.                 }
  926.             }
  927.         }
  928.         if (size >= needed)
  929.             return size;
  930.  
  931.         lastsize = end = 0;
  932.     }
  933.     for (m = *map; m; m = m->next) {
  934.         if (ISFREE(m) || m->links == 0xfffe ||
  935.             (m->links == 0xffff && (m->mflags & M_SHTEXT))) {
  936.             if (end == m->loc) {
  937.                 lastsize += m->len;
  938.             } else {
  939.                 lastsize = m->len;
  940.             }
  941.             end = m->loc + m->len;
  942.             if (lastsize > size) {
  943.                 if (needed && lastsize >= needed)
  944.                     return lastsize;
  945.                 size = lastsize;
  946.             }
  947.         }
  948.     }
  949.     return size;
  950. }
  951.  
  952. /*
  953.  * tot_rsize(map, flag): if flag == 1, return the total number of bytes in
  954.  * the given memory map; if flag == 0, return only the number of free
  955.  * bytes
  956.  */
  957.  
  958. long
  959. tot_rsize(map, flag)
  960.     MMAP map;
  961.     int flag;
  962. {
  963.     MEMREGION *m;
  964.     long size = 0;
  965.  
  966.     for (m = *map; m; m = m->next) {
  967.         if (flag || ISFREE(m) ||
  968.             (m->links == 0xffff && (m->mflags & M_SHTEXT))) {
  969.             size += m->len;
  970.         }
  971.     }
  972.     return size;
  973. }
  974.  
  975. /*
  976.  * alloc_region(MMAP map, ulong size, int mode): allocate a new region and
  977.  * attach it to the current process; returns the address at which the region
  978.  * was attached, or NULL. The mode argument is the memory protection mode to
  979.  * give to get_region, and in turn to mark_region.
  980.  */
  981.  
  982. virtaddr
  983. alloc_region(map, size, mode)
  984.     MMAP map;
  985.     ulong size;
  986.     int mode;
  987. {
  988.     MEMREGION *m;
  989.     PROC *proc = curproc;
  990.     virtaddr v;
  991.  
  992.     TRACELOW(("alloc_region(map,size: %lx,mode: %x)",size,mode));
  993.     if (!size) {
  994.         DEBUG(("alloc_region of zero bytes?!"));
  995.         return 0;
  996.     }
  997.  
  998.     m = get_region(map, size, mode);
  999.     if (!m) {
  1000.         TRACELOW(("alloc_region: get_region failed"));
  1001.         return 0;
  1002.     }
  1003.  
  1004. /* sanity check: even addresses only, please */
  1005.     assert((m->loc & MASKBITS) == 0);
  1006.  
  1007.     v = attach_region(proc, m);
  1008. /* NOTE: get_region returns a region with link count 1; since attach_region
  1009.  * increments the link count, we restore it after calling attach_region
  1010.  */
  1011.     m->links = 1;
  1012.     if (!v) {
  1013.         m->links = 0;
  1014.         free_region(m);
  1015.         TRACE(("alloc_region: attach_region failed"));
  1016.         return 0;
  1017.     }
  1018.     return v;
  1019. }
  1020.  
  1021. /*
  1022.  * routines for creating a copy of an environment, and a new basepage.
  1023.  * note that the memory regions created should immediately be attached to
  1024.  * a process! Also note that create_env always operates in ST RAM, but
  1025.  * create_base might not.
  1026.  */
  1027.  
  1028. MEMREGION *
  1029. create_env(env, flags)
  1030.     const char *env;
  1031.     ulong flags;
  1032. {
  1033.     long size;
  1034.     MEMREGION *m;
  1035.     virtaddr v;
  1036.     const char *old;
  1037.     char *new;
  1038.     short protmode;
  1039.  
  1040.     if (!env) {
  1041.         env = ((BASEPAGE *)curproc->base)->p_env;
  1042.             /* duplicate parent's environment */
  1043.     }
  1044.     size = 2;
  1045.     old = env;
  1046.     while (*env || *(env+1))
  1047.         env++,size++;
  1048.  
  1049.     protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
  1050.  
  1051.     v = alloc_region(core, size, protmode);
  1052.     /* if core fails, try alt */
  1053.     if (!v)
  1054.         v = alloc_region(alt, size, protmode);
  1055.  
  1056.     if (!v) {
  1057.         DEBUG(("create_env: alloc_region failed"));
  1058.         return (MEMREGION *)0;
  1059.     }
  1060.     m = addr2mem(v);
  1061.  
  1062. /* copy the old environment into the new */
  1063.     new = (char *) m->loc;
  1064.     TRACE(("copying environment: from %lx to %lx", old, new));
  1065.     while (size > 0) {
  1066.         *new++ = *old++;
  1067.         --size;
  1068.     }
  1069.     TRACE(("finished copying environment"));
  1070.  
  1071.     return m;
  1072. }
  1073.  
  1074. static void terminateme(code)
  1075.     int code;
  1076. {
  1077.     Pterm (code);
  1078. }
  1079.  
  1080. MEMREGION *
  1081. create_base(cmd, env, flags, prgsize, execproc, s, f, fh, xp)
  1082.     const char *cmd;
  1083.     MEMREGION *env;
  1084.     ulong flags, prgsize;
  1085.     PROC *execproc;
  1086.     SHTEXT *s;
  1087.     FILEPTR *f;
  1088.     FILEHEAD *fh;
  1089.     XATTR *xp;
  1090. {
  1091.     long len = 0, minalt = 0, coresize, altsize;
  1092.     MMAP map;
  1093.     MEMREGION *m, *savemem = 0;
  1094.     BASEPAGE *b, *bparent = 0;
  1095.     PROC *parent = 0;
  1096.     short protmode;
  1097.     int i, ismax = 1;
  1098.  
  1099. /* if we're about to do an exec tell max_rsize which of the exec'ing
  1100.    process regions will be freed, but don't free them yet so the process
  1101.    can still get an ENOMEM...
  1102. */
  1103.     if (execproc) {
  1104.         for (i = 0; i < execproc->num_reg; i++) {
  1105.             m = execproc->mem[i];
  1106.             if (m && m->links == 1)
  1107.                 m->links = 0xfffe;
  1108.         }
  1109.  
  1110. /* if parents mem saved because of a blocking fork that can be restored too
  1111. */
  1112.         if (NULL != (parent = pid2proc(execproc->ppid)) &&
  1113.             parent->wait_q == WAIT_Q && 
  1114.             parent->wait_cond == (long)execproc) {
  1115.             for (i = 0; i < parent->num_reg; i++) {
  1116.                 m = parent->mem[i];
  1117.                 if (m && (m->mflags & M_FSAVED)) {
  1118.                     m->links = 0xfffe;
  1119.                     savemem = m;
  1120.                     break;
  1121.                 }
  1122.             }
  1123.         }
  1124.     }
  1125.  
  1126. /* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
  1127.    RAM if enough is available. "enough" is: if more alt ram than ST ram,
  1128.    load there; otherwise, if more than (minalt+1)*128K alt ram available
  1129.    for heap space, load in alt ram ("minalt" is the high byte of flags)
  1130.  */
  1131. again2:
  1132.     if (flags & (F_ALTLOAD|F_SHTEXT)) {
  1133.         minalt = (flags & F_MINALT) >> 28L;
  1134.         minalt = len = (minalt+1)*128*1024L + prgsize + 256;
  1135.         if ((flags & F_MINALT) == F_MINALT)
  1136.             len = 0;
  1137.         else
  1138.             ismax = 0;
  1139.     }
  1140. again1:
  1141.     if (flags & F_ALTLOAD) {
  1142.         coresize = max_rsize(core, len);
  1143.         altsize = max_rsize(alt, len);
  1144.         if (altsize >= coresize) {
  1145.             map = alt;
  1146.             len = altsize;
  1147.         } else {
  1148.             if (altsize >= minalt) {
  1149.                 map = alt;
  1150.                 len = altsize;
  1151.             } else {
  1152.                 map = core;
  1153.                 len = coresize;
  1154.             }
  1155.         }
  1156.     }
  1157.     else
  1158.         len = max_rsize((map = core), len);
  1159.  
  1160.     if (savemem)
  1161.         savemem->links = 1;
  1162.  
  1163.     if (curproc->maxmem && len > curproc->maxmem) {
  1164.         if (ismax >= 0)
  1165.             len = curproc->maxmem;
  1166.         else if (len > curproc->maxmem+fh->ftext)
  1167.             len = curproc->maxmem+fh->ftext;
  1168.     }
  1169.  
  1170. /* make sure that a little bit of memory is left over */
  1171.     if (len > 2*KEEP_MEM) {
  1172.         len -= KEEP_MEM;
  1173.     }
  1174.  
  1175.     if (s && !s->text &&
  1176.         (!(flags & F_ALTLOAD) || map == alt || altsize < fh->ftext)) {
  1177.         if (len > fh->ftext + KERNEL_MEM)
  1178.             len -= fh->ftext + KERNEL_MEM;
  1179.         else
  1180.             len = 0;
  1181. #if 1
  1182.         if (prgsize && len < prgsize + 0x400) {
  1183.             if (!ismax) {
  1184.                 len = minalt + fh->ftext;
  1185.                 ismax = -1;
  1186.                 goto again1;
  1187.             }
  1188.             if ((s->text = addr2mem(alloc_region(map, fh->ftext, PROT_P)))) {
  1189.                 goto again2;
  1190.             }
  1191.         }
  1192. #endif
  1193.     }
  1194.  
  1195.     if (prgsize && len < prgsize + 0x400) {
  1196.         /* can't possibly load this file in its eligible regions */
  1197.         DEBUG(("create_base: max_rsize smaller than prgsize"));
  1198.  
  1199.         if (execproc) {
  1200. /* error, undo the above */
  1201.             for (i = 0; i < execproc->num_reg; i++) {
  1202.                 m = execproc->mem[i];
  1203.                 if (m && m->links == 0xfffe)
  1204.                     m->links = 1;
  1205.             }
  1206.         }
  1207.         if (s && !s->text) {
  1208.             kfree (s);
  1209.         }
  1210.         mint_errno = ENSMEM;
  1211.         return 0;
  1212.     }
  1213.     if (execproc) {
  1214. /* free exec'ing process memory... if the exec returns after this make it
  1215.    _exit (SIGKILL << 8);
  1216. */
  1217.         *((short *) (execproc->stack + ISTKSIZE + sizeof (void (*)()))) =
  1218.             (SIGKILL << 8);
  1219.         execproc->ctxt[SYSCALL].term_vec = (long)rts;
  1220.         execproc->ctxt[SYSCALL].pc = (long)terminateme;
  1221.         execproc->ctxt[SYSCALL].sr |= 0x2000;
  1222.         execproc->ctxt[SYSCALL].ssp = (long)(execproc->stack + ISTKSIZE);
  1223.  
  1224. /* save basepage p_parent */
  1225.         bparent = execproc->base->p_parent;
  1226.         if (parent) {
  1227.             if (savemem)
  1228.                 fork_restore(parent, savemem);
  1229. /* blocking forks keep the same basepage for parent and child,
  1230.    so this p_parent actually was our grandparents...  */
  1231.             bparent = parent->base;
  1232.         }
  1233.         for (i = 0; i < execproc->num_reg; i++) {
  1234.             m = execproc->mem[i];
  1235.             if (m && m->links == 0xfffe) {
  1236.                 execproc->mem[i] = 0;
  1237.                 execproc->addr[i] = 0;
  1238.                 if (m->mflags & M_SHTEXT_T) {
  1239.                     TRACE (("create_base: keeping sticky text segment (%lx, len %lx)",
  1240.                         m->loc, m->len));
  1241.                     m->links = 0xffff;
  1242.                 } else {
  1243.                     m->links = 0;
  1244.                     free_region(m);
  1245.                 }
  1246.             }
  1247.         }
  1248.     }
  1249.     protmode = (flags & F_PROTMODE) >> F_PROTSHIFT;
  1250.  
  1251.     m = 0;
  1252.     if (s && !s->f) {
  1253.         if (!s->text) {
  1254.             m = addr2mem(alloc_region(map, len + fh->ftext + KERNEL_MEM, protmode));
  1255.             if (!m ||
  1256.                 (((len > minalt &&
  1257.                 ((flags & F_MINALT) < F_MINALT) &&
  1258.                 max_rsize (map, -1) < fh->ftext) ||
  1259.                   0 == (s->text = addr2mem(alloc_region(map, fh->ftext, PROT_P))) ||
  1260.                   (m->next == s->text &&
  1261.                 !(detach_region (curproc, s->text), s->text = 0))) &&
  1262.                  shrink_region(m, fh->ftext))) {
  1263.                 if (m)
  1264.                     detach_region(curproc, m);
  1265.                 kfree (s);
  1266.                 mint_errno = ENSMEM;
  1267.                 return 0;
  1268.             }
  1269.             if (!s->text) {
  1270.                 s->text = m;
  1271.                 if (protmode != PROT_P)
  1272.                     mark_region(m, PROT_P);
  1273.                 m = 0;
  1274.             }
  1275.         }
  1276.         s = get_text_seg(f, fh, xp, s, 0);
  1277.         if (!s) {
  1278.             if (m)
  1279.                 detach_region(curproc, m);
  1280.             DEBUG(("create_base: unable to load shared text segment"));
  1281. /* mint_errno set in get_text_seg */
  1282.             return 0;
  1283.         }
  1284.     }
  1285.  
  1286.     if (!m) {
  1287.         m = addr2mem(alloc_region(map, len, protmode));
  1288.     }
  1289.     if (!m) {
  1290.         DEBUG(("create_base: alloc_region failed"));
  1291.         mint_errno = ENSMEM;
  1292.         return 0;
  1293.     }
  1294.     b = (BASEPAGE *)(m->loc);
  1295.  
  1296.     zero((char *)b, (long)sizeof(BASEPAGE));
  1297.     b->p_lowtpa = (long)b;
  1298.     b->p_hitpa = m->loc + m->len;
  1299.     b->p_env = (char *)env->loc;
  1300.     b->p_flags = flags;
  1301.  
  1302.     if (execproc) {
  1303.         execproc->base = b;
  1304.         b->p_parent = bparent;
  1305.     }
  1306.  
  1307.     if (cmd)
  1308.         strncpy(b->p_cmdlin, cmd, 126);
  1309.     return m;
  1310. }
  1311.  
  1312. /*
  1313.  * load_region(): loads the program with the given file name
  1314.  * into a new region, and returns a pointer to that region. On
  1315.  * an error, returns 0 and leaves the error number in mint_errno.
  1316.  * "env" points to an already set up environment region, as returned
  1317.  * by create_env. On success, "xp" points to the file attributes, which
  1318.  * Pexec has already determined, and "fp" points to the programs
  1319.  * prgflags. "text" is a pointer to a MEMREGION
  1320.  * pointer, which will be set to the region occupied by the shared
  1321.  * text segment of this program (if applicable).
  1322.  */
  1323.  
  1324. MEMREGION *
  1325. load_region(filename, env, cmdlin, xp, text, fp, isexec)
  1326.     const char *filename;
  1327.     MEMREGION *env;
  1328.     const char *cmdlin;
  1329.     XATTR *xp;        /* attributes for the file just loaded */
  1330.     MEMREGION **text;    /* set to point to shared text region,
  1331.                    if any */
  1332.     long *fp;        /* prgflags for this file */
  1333.     int isexec;        /* this is an exec*() (overlay) */
  1334. {
  1335.     FILEPTR *f;
  1336.     DEVDRV *dev;
  1337.     MEMREGION *reg, *shtext;
  1338.     BASEPAGE *b;
  1339.     long size, start;
  1340.     FILEHEAD fh;
  1341.     SHTEXT *s;
  1342.  
  1343. /* bug: this should be O_DENYW mode, not O_DENYNONE */
  1344. /* we must use O_DENYNONE because of the desktop and because of the
  1345.  * TOS file system brain-damage
  1346.  */
  1347.     f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
  1348.     if (!f) {
  1349.         return 0;        /* mint_errno set by do_open */
  1350.     }
  1351.  
  1352.     dev = f->dev;
  1353.     size = (*dev->read)(f, (void *)&fh, (long)sizeof(fh));
  1354.     if (fh.fmagic != GEMDOS_MAGIC || size != (long)sizeof(fh)) {
  1355.         DEBUG(("load_region: file not executable"));
  1356.         mint_errno = ENOEXEC;
  1357. failed:
  1358.         do_close(f);
  1359.         return 0;
  1360.     }
  1361.  
  1362.     if (((fh.flag & F_PROTMODE) >> F_PROTSHIFT) > PROT_MAX_MODE) {
  1363.         DEBUG (("load_region: invalid protection mode changed to private"));
  1364.         fh.flag = (fh.flag & ~F_PROTMODE) | F_PROT_P;
  1365.     }
  1366.     *fp = fh.flag;
  1367.  
  1368.     if (fh.flag & F_SHTEXT) {
  1369.         TRACE(("loading shared text segment"));
  1370.         s = get_text_seg(f, &fh, xp, 0L, isexec);
  1371.         if (!s) {
  1372.             DEBUG(("load_region: unable to get shared text segment"));
  1373. /* mint_errno set in get_text_seg */
  1374.             goto failed;
  1375.         }
  1376.         size = fh.fdata + fh.fbss;
  1377.         shtext = s->text;
  1378.     } else {
  1379.         size = fh.ftext + fh.fdata + fh.fbss;
  1380.         shtext = 0;
  1381.         s = 0;
  1382.     }
  1383.  
  1384.     env->links++;
  1385.     if (s && !shtext) {
  1386.         reg = create_base(cmdlin, env, fh.flag, size,
  1387.             isexec ? curproc : 0L, s, f, &fh, xp);
  1388.         shtext = s->text;
  1389.     } else {
  1390.         if (shtext)
  1391.             shtext->links++;
  1392.         reg = create_base(cmdlin, env, fh.flag, size,
  1393.             isexec ? curproc : 0L, 0L, 0L, 0L, 0L);
  1394.         if (shtext) {
  1395.             shtext->links--;
  1396. #if 1
  1397. /* if create_base failed maybe the (sticky) text segment itself is
  1398.  * fragmenting memory... force it reloaded and have a second try
  1399.  */
  1400.             if (!reg && shtext->links == 1 && isexec) {
  1401.                 s->f = 0;
  1402.                 f->links--;
  1403.                 detach_region(curproc, shtext);
  1404.                 s = get_text_seg(f, &fh, xp, 0L, isexec);
  1405.                 if (!s) {
  1406.                     DEBUG(("load_region: unable to get shared text segment"));
  1407.                     goto failed;
  1408.                 }
  1409.                 reg = create_base(cmdlin, env, fh.flag, size,
  1410.                     curproc, s, f, &fh, xp);
  1411.                 shtext = s->text;
  1412.             }
  1413. #endif
  1414.         }
  1415.     }
  1416.     env->links--;
  1417.     if (reg && size+1024L > reg->len) {
  1418.         DEBUG(("load_region: insufficient memory to load"));
  1419.         detach_region(curproc, reg);
  1420.         reg = 0;
  1421.         mint_errno = ENSMEM;
  1422.     }
  1423.  
  1424.     if (reg == 0) {
  1425.         if (shtext) {
  1426.             detach_region(curproc, shtext);
  1427.         }
  1428.         goto failed;
  1429.     }
  1430.  
  1431.     b = (BASEPAGE *)reg->loc;
  1432.     b->p_flags = fh.flag;
  1433.     if (shtext) {
  1434.         b->p_tbase = shtext->loc;
  1435.         b->p_tlen = 0;
  1436.         b->p_dbase = b->p_lowtpa + 256;
  1437.     } else {
  1438.         b->p_tbase = b->p_lowtpa + 256;
  1439.         b->p_tlen = fh.ftext;
  1440.         b->p_dbase = b->p_tbase + b->p_tlen;
  1441.     }
  1442.     b->p_dlen = fh.fdata;
  1443.     b->p_bbase = b->p_dbase + b->p_dlen;
  1444.     b->p_blen = fh.fbss;
  1445.  
  1446. /* if shared text, then we start loading at the end of the
  1447.  * text region, since that is already set up
  1448.  */
  1449.     if (shtext) {
  1450.     /* skip over text info */
  1451.         size = fh.fdata;
  1452.         start = fh.ftext;
  1453.     } else {
  1454.         size = fh.ftext + fh.fdata;
  1455.         start = 0;
  1456.     }
  1457.  
  1458.     mint_errno = (int)load_and_reloc(f, &fh, (char *)b+256, start,
  1459.             size, b);
  1460.  
  1461.     if (mint_errno) {
  1462.         detach_region(curproc, reg);
  1463.         if (shtext) detach_region(curproc, shtext);
  1464.         goto failed;
  1465.     }
  1466.  
  1467.     if (fh.flag & F_FASTLOAD)            /* fastload bit */
  1468.         size = b->p_blen;
  1469.     else
  1470.         size = b->p_hitpa - b->p_bbase;
  1471.     if (size > 0) {
  1472.         start = b->p_bbase;
  1473.         if (start & 1) {
  1474.             *(char *)start = 0;
  1475.             start++;
  1476.             --size;
  1477.         }
  1478.         zero((char *)start, size);
  1479.     }
  1480.  
  1481.     do_close(f);
  1482.     *text = shtext;
  1483.     return reg;
  1484. }
  1485.  
  1486. /*
  1487.  * load_and_reloc(f, fh, where, start, nbytes): load and relocate from
  1488.  * the open GEMDOS executable file f "nbytes" bytes starting at offset
  1489.  * "start" (relative to the end of the file header, i.e. from the first
  1490.  * byte of the actual program image in the file). "where" is the address
  1491.  * in (physical) memory into which the loaded image must be placed; it is
  1492.  * assumed that "where" is big enough to hold "nbytes" bytes!
  1493.  */
  1494.  
  1495. long
  1496. load_and_reloc(f, fh, where, start, nbytes, base)
  1497.     FILEPTR *f;
  1498.     FILEHEAD *fh;
  1499.     char *where;
  1500.     long start;
  1501.     long nbytes;
  1502.     BASEPAGE *base;
  1503. {
  1504.     unsigned char c, *next;
  1505.     long r;
  1506.     DEVDRV *dev;
  1507. #define LRBUFSIZ 8196
  1508.     static unsigned char buffer[LRBUFSIZ];
  1509.     long fixup, size, bytes_read;
  1510.     long reloc;
  1511.  
  1512.  
  1513. TRACE(("load_and_reloc: %ld to %ld at %lx", start, nbytes+start, where));
  1514.     dev = f->dev;
  1515.  
  1516.     r = (*dev->lseek)(f, start+sizeof(FILEHEAD), SEEK_SET);
  1517.     if (r < 0) return r;
  1518.     r = (*dev->read)(f, where, nbytes);
  1519.     if (r != nbytes) {
  1520.         DEBUG(("load_region: unexpected EOF"));
  1521.         return ENOEXEC;
  1522.     }
  1523.  
  1524. /* now do the relocation */
  1525. /* skip over symbol table, etc. */
  1526.     r = (*dev->lseek)(f, sizeof(FILEHEAD) + fh->ftext + fh->fdata +
  1527.             fh->fsym, SEEK_SET);
  1528.     if (r < 0) return ENOEXEC;
  1529.  
  1530.     if (fh->reloc != 0 || (*dev->read)(f, (char *)&fixup, 4L) != 4L
  1531.         || fixup == 0) {
  1532.         return 0;    /* no relocation to be performed */
  1533.     }
  1534.  
  1535.     size = LRBUFSIZ;
  1536.     bytes_read = 0;
  1537.     next = buffer;
  1538.  
  1539.     do {
  1540.         if (fixup >= nbytes + start) {
  1541.             TRACE(("load_region: end of relocation at %ld", fixup));
  1542.             break;
  1543.         }
  1544.         else if (fixup >= start) {
  1545.             reloc = *((long *)(where + fixup - start));
  1546.             if (reloc < fh->ftext) {
  1547.                 reloc += base->p_tbase;
  1548.             } else if (reloc < fh->ftext + fh->fdata && base->p_dbase) {
  1549.                 reloc += base->p_dbase - fh->ftext;
  1550.             } else if (reloc < fh->ftext + fh->fdata + fh->fbss && base->p_bbase) {
  1551.                 reloc += base->p_bbase - (fh->ftext + fh->fdata);
  1552.             } else {
  1553.                 DEBUG(("load_region: bad relocation: %ld", reloc));
  1554.                 if (base->p_dbase)
  1555.                     reloc += base->p_dbase - fh->ftext;    /* assume data reloc */
  1556.                 else if (base->p_bbase)
  1557.                     reloc += base->p_bbase - (fh->ftext + fh->fdata);
  1558.                 else
  1559.                     return ENOEXEC;
  1560.             }
  1561.             *((long *)(where + fixup - start)) = reloc;
  1562.         }
  1563.         do {
  1564.             if (!bytes_read) {
  1565.                 bytes_read =
  1566.                     (*dev->read)(f,(char *)buffer,size);
  1567.                 next = buffer;
  1568.             }
  1569.             if (bytes_read < 0) {
  1570.                 DEBUG(("load_region: EOF in relocation"));
  1571.                 return ENOEXEC;
  1572.             }
  1573.             else if (bytes_read == 0)
  1574.                 c = 0;
  1575.             else {
  1576.                 c = *next++; bytes_read--;
  1577.             }
  1578.             if (c == 1) fixup += 254;
  1579.         } while (c == 1);
  1580.         fixup += ( (unsigned) c) & 0xff;
  1581.     } while (c);
  1582.  
  1583.     return 0;
  1584. }
  1585.  
  1586. /*
  1587.  * function to check for existence of a shared text region
  1588.  * corresponding to file "f", and if none is found, to create one
  1589.  * the memory region being returned is attached to the current
  1590.  * process
  1591.  */
  1592.  
  1593. SHTEXT *
  1594. get_text_seg(f, fh, xp, s, noalloc)
  1595.     FILEPTR *f;
  1596.     FILEHEAD *fh;
  1597.     XATTR *xp;
  1598.     SHTEXT *s;
  1599.     int noalloc;
  1600. {
  1601.     MEMREGION *m;
  1602.     long r;
  1603.     BASEPAGE b;
  1604.  
  1605.     if (s) {
  1606.         m = s->text;
  1607.     } else {
  1608.         s = text_reg;
  1609.  
  1610.         while(s) {
  1611.             if (s->f && samefile(&f->fc, &s->f->fc) &&
  1612.                 xp->mtime == s->mtime &&
  1613.                 xp->mdate == s->mdate)
  1614.             {
  1615.                 m = s->text;
  1616. /* Kludge for unattached shared region */
  1617.                 if (m->links == 0xffff)
  1618.                     m->links = 0;
  1619.                 if (attach_region(curproc, m)) {
  1620. TRACE(("re-using shared text region %lx", m));
  1621.                     return s;
  1622.                 }
  1623.                 else {
  1624.                     mint_errno = ENSMEM;
  1625.                     return 0;
  1626.                 }
  1627.             }
  1628.             s = s->next;
  1629.         }
  1630.  
  1631. /* hmmm, not found; OK, we'll have to create a new text region */
  1632.  
  1633.         s = kmalloc(SIZEOF(SHTEXT));
  1634.         if (!s) {
  1635.             mint_errno = ENSMEM;
  1636.             return 0;
  1637.         }
  1638.         if (noalloc) {
  1639.             s->f = 0;
  1640.             s->text = 0;
  1641.             return s;
  1642.         }
  1643.         m = 0;
  1644.     }
  1645.  
  1646.     if (!m) {
  1647. /* actually, I can't see why loading in TT RAM is ever undesireable,
  1648.  * since shared text programs should be very clean (and since only
  1649.  * the text segment is going in there). But better safe than sorry.
  1650.  */
  1651.         if (fh->flag & F_ALTLOAD) {
  1652.             m = addr2mem(alloc_region(alt, fh->ftext, PROT_P));
  1653.         }
  1654.         if (!m)
  1655.             m = addr2mem(alloc_region(core, fh->ftext, PROT_P));
  1656.     }
  1657.  
  1658.     if (!m) {
  1659.         kfree(s);
  1660.         mint_errno = ENSMEM;
  1661.         return 0;
  1662.     }
  1663.  
  1664. /* set up a fake "basepage" for load_and_reloc
  1665.  * note: the 0 values should make load_and_reloc
  1666.  * barf on any attempts at data relocation, since we have
  1667.  * no data segment
  1668.  */
  1669. TRACE(("attempting to create shared text region"));
  1670.  
  1671.     b.p_tbase = m->loc;
  1672.     b.p_tlen = fh->ftext;
  1673.     b.p_dbase = 0;
  1674.     b.p_dlen = 0;
  1675.     b.p_bbase = b.p_blen = 0;
  1676.  
  1677.     r = load_and_reloc(f, fh, (char *)m->loc, 0, fh->ftext, &b);
  1678.     if (r) {
  1679.         detach_region(curproc, m);
  1680.         kfree(s);
  1681.         return 0;
  1682.     }
  1683.  
  1684. /* region has valid shared text data */
  1685.     m->mflags |= M_SHTEXT;
  1686. #if 1
  1687.     if (xp->mode & 01000)
  1688. #endif
  1689. /* make it sticky (this should depend on the files mode!?) */
  1690.     m->mflags |= M_SHTEXT_T;
  1691.  
  1692. /*
  1693.  * KLUDGE: to make sure we always have up to date shared text
  1694.  * info, even across a network, we leave the file passed
  1695.  * to us open with DENYWRITE mode, so that nobody will
  1696.  * modify it.
  1697.  */
  1698.     f->links++;    /* keep the file open longer */
  1699.  
  1700. /* BUG: what if someone already has the file open for
  1701.  * writing? Then we could get screwed...
  1702.  */
  1703.     f->flags = (f->flags & ~O_SHMODE) | O_DENYW;
  1704.     s->f = f;
  1705.     s->text = m;
  1706.     s->next = text_reg;
  1707.     s->mtime = xp->mtime;
  1708.     s->mdate = xp->mdate;
  1709.     text_reg = s;
  1710. TRACE(("shared text region %lx created", m));
  1711.     return s;
  1712. }
  1713.  
  1714. /*
  1715.  * function to just check for existence of a shared text region
  1716.  * corresponding to file "f"
  1717.  */
  1718.  
  1719. MEMREGION *
  1720. find_text_seg(f)
  1721.     FILEPTR *f;
  1722. {
  1723.     SHTEXT *s;
  1724.  
  1725.     for (s = text_reg; s; s = s->next) {
  1726.         if (s->f && samefile(&f->fc, &s->f->fc))
  1727.             return s->text;
  1728.     }
  1729.     return 0;
  1730. }
  1731.  
  1732. /*
  1733.  * exec_region(p, mem, thread): create a child process out of a mem region
  1734.  * "p" is the process structure set up by the parent; it may be "curproc",
  1735.  * if we're overlaying. "mem" is the loaded memory region returned by
  1736.  * "load region". Any open files (other than the standard handles) owned
  1737.  * by "p" are closed, and if thread !=0 all memory is released; the caller
  1738.  * must explicitly attach the environment and base region. The caller must
  1739.  * also put "p" on the appropriate queue (most likely READY_Q).
  1740.  */
  1741.  
  1742. extern long mint_dos(), mint_bios();
  1743.  
  1744. void rts() {}        /* dummy termination routine */
  1745.  
  1746. PROC *
  1747. exec_region(p, mem, thread)
  1748.     PROC      *p;
  1749.     MEMREGION *mem;
  1750.     int thread;
  1751. {
  1752.     BASEPAGE *b;
  1753.     FILEPTR *f;
  1754.     int i;
  1755.     MEMREGION *m;
  1756.  
  1757.     TRACE(("exec_region"));
  1758.  
  1759.     b = (BASEPAGE *) mem->loc;
  1760.  
  1761.     cpush((void *)b->p_tbase, b->p_tlen);    /* flush cached versions of the text */
  1762.     
  1763. /* set some (undocumented) variables in the basepage */
  1764.     b->p_defdrv = p->curdrv;
  1765.     for (i = 0; i < 6; i++)
  1766.         b->p_devx[i] = i;
  1767.  
  1768.     p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
  1769.     p->base = b;
  1770.  
  1771. /* close extra open files */
  1772.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  1773.         if ( (f = p->handle[i]) != 0 && (p->fdflags[i] & FD_CLOEXEC) ) {
  1774.             do_pclose(p, f);
  1775.             p->handle[i] = 0;
  1776.         }
  1777.     }
  1778.  
  1779. /* initialize memory */
  1780.     recalc_maxmem(p);
  1781.     if (p->maxmem) {
  1782.         shrink_region(mem, p->maxmem);
  1783.         b->p_hitpa = b->p_lowtpa + mem->len;
  1784.     }
  1785.  
  1786.     p->memflags = b->p_flags;
  1787.  
  1788.     if (!thread) {
  1789.         for (i = 0; i < p->num_reg; i++) {
  1790.             m = p->mem[i];
  1791.             if (m) {
  1792.                 m->links--;
  1793. #if 1
  1794.                 if (m->links <= 0) {
  1795.                     if (!m->links) {
  1796.                         if (m->mflags & M_SHTEXT_T) {
  1797.                             TRACE (("exec_region: keeping sticky text segment (%lx, len %lx)",
  1798.                                 m->loc, m->len));
  1799.                             m->links = 0xffff;
  1800.                         } else
  1801.                             free_region(m);
  1802.                     } else
  1803.                         ALERT ("exec_region: region %lx bogus link count %d, not freed (len %lx)",
  1804.                             m->loc, m->links, m->len);
  1805.                 }
  1806. #else
  1807.                 if (m->links <= 0)
  1808.                     free_region(m);
  1809. #endif
  1810.             }
  1811.         }
  1812.         if (p->num_reg > NUM_REGIONS) {
  1813.             /*
  1814.              * If the proc struct has a larger mem array than
  1815.              * the default, then free it and allocate a
  1816.              * default-sized one.
  1817.              */
  1818.  
  1819.             /*
  1820.              * hoo ha! Memory protection problem here. Use
  1821.              * temps and pre-clear p->mem so memprot doesn't try
  1822.              * to walk these structures as we're freeing and
  1823.              * reallocating them!  (Calling kmalloc can cause
  1824.              * a table walk if the alloc results in calling
  1825.              * get_region.)
  1826.              */
  1827.             void *pmem, *paddr;
  1828.  
  1829.             pmem = p->mem;
  1830.             paddr = p->addr;
  1831.             p->mem = NULL; p->addr = NULL;
  1832.             kfree(pmem); kfree(paddr);
  1833.  
  1834.             pmem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
  1835.             paddr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
  1836.             assert(pmem && paddr);
  1837.             p->mem = pmem;
  1838.             p->addr = paddr;
  1839.             p->num_reg = NUM_REGIONS;
  1840.         }
  1841.         zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
  1842.         zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
  1843.     }
  1844.  
  1845. /* initialize signals */
  1846.     p->sigmask = 0;
  1847.     for (i = 0; i < NSIG; i++) {
  1848.         if (p->sighandle[i] != SIG_IGN) {
  1849.             p->sighandle[i] = SIG_DFL;
  1850.             p->sigflags[i] = 0;
  1851.             p->sigextra[i] = 0;
  1852.         }
  1853.     }
  1854.  
  1855. /* zero the user registers, and set the FPU in a "clear" state */
  1856.     for (i = 0; i < 15; i++)
  1857.         p->ctxt[CURRENT].regs[i] = 0;
  1858.     p->ctxt[CURRENT].sr = 0;
  1859.     p->ctxt[CURRENT].fstate[0] = 0;
  1860.  
  1861. /* set PC, stack registers, etc. appropriately */
  1862.     p->ctxt[CURRENT].pc = b->p_tbase;
  1863.  
  1864. /* The "-0x20" is to make sure that syscall.s won't run past the end of
  1865.  * memory when the user makes a system call and doesn't push very many
  1866.  * parameters -- syscall always tries to copy the maximum possible number
  1867.  * of parms.
  1868.  *
  1869.  * NOTE: there's a sanity check here in case programs Mshrink a basepage
  1870.  * without fixing the p_hitpa field in the basepage; this is to ensure
  1871.  * compatibility with older versions of MiNT, which ignore p_hitpa.
  1872.  */
  1873.     if (valid_address(b->p_hitpa - 0x20))
  1874.         p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
  1875.     else
  1876.         p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
  1877.  
  1878.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1879.     p->ctxt[CURRENT].term_vec = (long)rts;
  1880.  
  1881. /* set up stack for process */
  1882.     *((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
  1883.  
  1884. /* check for a valid text region. some compilers (e.g. Lattice 3) just throw
  1885.    everything into the text region, including data; fork() must be careful
  1886.    to save the whole region, then. We assume that if the compiler (or
  1887.    assembler, or whatever) goes to the trouble of making separate text, data,
  1888.    and bss regions, then the text region is code and isn't modified and
  1889.    fork doesn't have to save it.
  1890.  */
  1891.     if (b->p_blen != 0 || b->p_dlen != 0)
  1892.         p->txtsize = b->p_tlen;
  1893.     else
  1894.         p->txtsize = 0;
  1895.  
  1896. /*
  1897.  * An ugly hack: dLibs tries to poke around in the parent's address space
  1898.  * to find stuff. For now, we'll allow this by faking a pointer into
  1899.  * the parent's address space in the place in the basepage where dLibs is
  1900.  * expecting it. This ugly hack only works correctly if the Pexec'ing
  1901.  * program (i.e. curproc) is in user mode.
  1902.  */
  1903.     if (curproc != rootproc)
  1904.         curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
  1905.  
  1906.     return p;
  1907. }
  1908.  
  1909. /*
  1910.  * misc. utility routines
  1911.  */
  1912.  
  1913. /*
  1914.  * long memused(p): return total memory allocated to process p
  1915.  */
  1916.  
  1917. long
  1918. memused(p)
  1919.     PROC *p;
  1920. {
  1921.     int i;
  1922.     long size;
  1923.  
  1924.     /* a ZOMBIE owns no memory and its mem array ptr is zero */
  1925.     if (p->mem == NULL) return 0;
  1926.  
  1927.     size = 0;
  1928.     for (i = 0; i < p->num_reg; i++) {
  1929.         if (p->mem[i]) {
  1930.             if (p->mem[i]->mflags & (M_SEEN|M_FSAVED))
  1931.                 continue;    /* count links only once */
  1932.             p->mem[i]->mflags |= M_SEEN;
  1933.             size += p->mem[i]->len;
  1934.         }
  1935.     }
  1936.     for (i = 0; i < p->num_reg; i++) {
  1937.         if (p->mem[i])
  1938.             p->mem[i]->mflags &= ~M_SEEN;
  1939.     }
  1940.     return size;
  1941. }
  1942.  
  1943. /* 
  1944.  * recalculate the maximum memory limit on a process; this limit depends
  1945.  * on the max. allocated memory and max. total memory limits set by
  1946.  * p_setlimit (see dos.c), and (perhaps) on the size of the program
  1947.  * that the process is executing. whenever any of these things
  1948.  * change (through p_exec or p_setlimit) this routine must be called
  1949.  */
  1950.  
  1951. void
  1952. recalc_maxmem(p)
  1953.     PROC *p;
  1954. {
  1955.     BASEPAGE *b;
  1956.     long siz;
  1957.  
  1958.     b = (BASEPAGE *)p->base;
  1959.     if (b)
  1960.         siz = b->p_tlen + b->p_dlen + b->p_blen;
  1961.     else
  1962.         siz = 0;
  1963.     p->maxmem = 0;
  1964.     if (p->maxdata) {
  1965.         p->maxmem = p->maxdata + siz;
  1966.     }
  1967.  
  1968.     if (p->maxcore) {
  1969.         if (p->maxmem == 0 || p->maxmem > p->maxcore)
  1970.             p->maxmem = p->maxcore;
  1971.     }
  1972.     if (p->maxmem && p->maxmem < siz)
  1973.         p->maxmem = siz;
  1974. }
  1975.  
  1976. /*
  1977.  * valid_address: checks to see if the indicated address falls within
  1978.  * memory attached to the current process
  1979.  */
  1980.  
  1981. int
  1982. valid_address(addr)
  1983.     long addr;
  1984. {
  1985.     int i;
  1986.     MEMREGION *m;
  1987.  
  1988.     for (i = 0; i < curproc->num_reg; i++) {
  1989.         if ((m = curproc->mem[i]) != 0) {
  1990.             if (addr >= m->loc && addr <= m->loc + m->len)
  1991.                 return 1;
  1992.         }
  1993.     }
  1994.     return 0;
  1995. }
  1996.  
  1997. /*
  1998.  * convert an address to a memory region; this works only in
  1999.  * the ST RAM and TT RAM maps, and will fail for memory that
  2000.  * MiNT doesn't own or which is virtualized
  2001.  */
  2002.  
  2003. MEMREGION *
  2004. addr2region(addr)
  2005.     long addr;
  2006. {
  2007.     unsigned long ua = (unsigned long) addr;
  2008.  
  2009.     extern ulong mint_top_st, mint_top_tt;
  2010.     MEMREGION *r;
  2011.     MMAP map;
  2012.  
  2013.     if (ua < mint_top_st) {
  2014.         map = core;
  2015.     } else if (ua < mint_top_tt) {
  2016.         map = alt;
  2017.     } else {
  2018.         return 0;
  2019.     }
  2020.  
  2021.     for (r = *map; r; r = r->next) {
  2022.         if (addr >= r->loc && addr < r->loc + r->len)
  2023.             return r;
  2024.     }
  2025.     return 0;
  2026. }
  2027.  
  2028. /*
  2029.  * some debugging stuff
  2030.  */
  2031.  
  2032. void
  2033. DUMP_ALL_MEM()
  2034. {
  2035. #ifdef DEBUG_INFO
  2036.     DUMPMEM(ker);
  2037.     DUMPMEM(core);
  2038.     DUMPMEM(alt);
  2039.     FORCE("new memory region descriptor pages: %d", num_reg_requests);
  2040. #endif
  2041. }
  2042.  
  2043. void
  2044. DUMPMEM(map)
  2045.     MMAP map;
  2046. {
  2047. #ifdef DEBUG_INFO
  2048.     MEMREGION *m;
  2049.  
  2050.     m = *map;
  2051.     FORCE("%s memory dump: starting at region %lx",
  2052.         (map == ker ? "ker" : (map == core ? "core" : "alt")), m);
  2053.     while (m) {
  2054.         FORCE("%ld bytes at %lx (%d links, mflags %x); next %lx", m->len, m->loc,
  2055.             m->links, m->mflags, m->next);
  2056.         m = m->next;
  2057.     }
  2058. #else
  2059.     UNUSED(map);
  2060. #endif
  2061. }
  2062.  
  2063. void
  2064. sanity_check(map)
  2065.     MMAP map;
  2066. {
  2067. #ifdef SANITY_CHECK
  2068.     MEMREGION *m, *nxt;
  2069.     long end;
  2070.  
  2071.     m = *map;
  2072.     while (m) {
  2073.         nxt = m->next;
  2074.         if (nxt) {
  2075.             end = m->loc + m->len;
  2076.             if (m->loc < nxt->loc && end > nxt->loc) {
  2077.                 FATAL("MEMORY CHAIN CORRUPTED");
  2078.             }
  2079.             else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
  2080.                 ALERT("Continguous memory regions not merged!");
  2081.             }
  2082.         }
  2083.         m = nxt;
  2084.     }
  2085. #else
  2086.     UNUSED(map);
  2087. #endif
  2088. }
  2089.